﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.IO;
using FarseerPhysics.Dynamics;

//This class handles the physical elements of the level

namespace Doodleberg
{
    class Level
    {
        public List<GravityBox> gravityBoxes { get; private set; }
        public List<List<Line>> lines { get; private set; }
        public Goal goal { get; private set; }
        public Ball ball { get; private set; }

        public World phyWorld;

        public Texture2D tex_ball;
        public Texture2D tex_goal;
        public Texture2D tex_linedrawn;
        public Texture2D tex_linehard;
        public Texture2D tex_gravitybox;

        private List<string> levels;
        private int currentLevel;

        public bool isRunning;


        public Level(string progressionFilename)
        {
            phyWorld = new World(new Vector2(0, 9.8f));

            gravityBoxes = new List<GravityBox>();
            lines = new List<List<Line>>();
            goal = new Goal(Vector2.Zero, 0);
            //ball = new Ball(Vector2.Zero, 25);

            //Parse levels
            TextReader reader;
            reader = new StreamReader("Levels/progression.txt");
            levels = new List<string>();
            string temp = "";
            while (temp != null)
            {
                temp = reader.ReadLine();
                if (temp != null)
                    levels.Add(temp);
            }
            reader.Close();

            currentLevel = -1;
        }


        public void loadContent()
        {
            tex_ball = Global.gameProperties.content.Load<Texture2D>("ball");
            tex_goal = Global.gameProperties.content.Load<Texture2D>("goal");
            tex_linedrawn = Global.gameProperties.content.Load<Texture2D>("line_drawn");
            tex_linehard = Global.gameProperties.content.Load<Texture2D>("line_hard");
            tex_gravitybox = Global.gameProperties.content.Load<Texture2D>("gravitybox");
        }


        public void advanceLevel()
        {
            Global.gameProperties.currentInk = 0;

            isRunning = false;
            Global.gameProperties.victory = false;
            if (areMoreLevels())
            {
                currentLevel++;
                loadLevel(levels[currentLevel]);
            }
        }


        public bool areMoreLevels()
        {
            return currentLevel + 1 < levels.Count;
        }


        public void loadLevel(string filename)
        {
            clear();
            StreamReader tempWriter = new StreamReader("Levels/" + filename);
            goal = new Goal(Vector2.Zero, 0.0f);
            goal.position = new Vector2(
                (float)Convert.ToDouble(tempWriter.ReadLine()),
                (float)Convert.ToDouble(tempWriter.ReadLine()));
            goal.radius = (float)Convert.ToDouble(tempWriter.ReadLine());

            //Read ball
            int tempcount = Convert.ToInt32(tempWriter.ReadLine());
            for (int c = 0; c < tempcount; c++)
            {
                float px = (float)Convert.ToDouble(tempWriter.ReadLine());
                float py = (float)Convert.ToDouble(tempWriter.ReadLine());
                Ball temp = new Ball(new Vector2(px, py), 11.5f);
                temp.startPosition = new Vector2(px, py);
                ball = temp;
                Console.WriteLine(temp.startPosition);
            }

            //Read grav boxes
            tempcount = Convert.ToInt32(tempWriter.ReadLine());
            for (int i = 0; i < tempcount; i++)
            {
                gravityBoxes.Add(new GravityBox(
                    new Rectangle(
                        Convert.ToInt32(tempWriter.ReadLine()),
                        Convert.ToInt32(tempWriter.ReadLine()),
                        Convert.ToInt32(tempWriter.ReadLine()),
                        Convert.ToInt32(tempWriter.ReadLine())),
                    new Vector2(
                        (float)Convert.ToDouble(tempWriter.ReadLine()),
                        (float)Convert.ToDouble(tempWriter.ReadLine()))
                        ));
            }

            //Read lines
            tempcount = Convert.ToInt32(tempWriter.ReadLine());
            List<Line> tempList = new List<Line>();
            for (int i = 0; i < tempcount; i++)
            {
                float v1x = (float)Convert.ToDouble(tempWriter.ReadLine());
                float v1y = (float)Convert.ToDouble(tempWriter.ReadLine());
                float v2x = (float)Convert.ToDouble(tempWriter.ReadLine());
                float v2y = (float)Convert.ToDouble(tempWriter.ReadLine());
                float res = (float)Convert.ToDouble(tempWriter.ReadLine());
                Line temp = new Line(
                    new Vector2(v1x, v1y),
                    new Vector2(v2x, v2y)
                    , res);
                temp.deletable = false;
                tempList.Add(temp);
            }
            lines.Add(tempList);

            //Obstacles (unused)
            tempcount = Convert.ToInt32(tempWriter.ReadLine());
            for (int i = 0; i < tempcount; i++)
            {
                int lef = Convert.ToInt32(tempWriter.ReadLine());
                int top = Convert.ToInt32(tempWriter.ReadLine());
                int wid = Convert.ToInt32(tempWriter.ReadLine());
                int hei = Convert.ToInt32(tempWriter.ReadLine());
                float res = (float)Convert.ToDouble(tempWriter.ReadLine());
            }

            tempWriter.Close();
            tempWriter.Dispose();
        }


        public void saveLevel(string filename)
        {
            StreamWriter tempWriter = new StreamWriter("Levels/" + filename);
            tempWriter.WriteLine(goal.position.X);
            tempWriter.WriteLine(goal.position.Y);
            tempWriter.WriteLine(goal.radius);

            //Write ball
            tempWriter.WriteLine(1);
            tempWriter.WriteLine(ball.position.X);
            tempWriter.WriteLine(ball.position.Y);

            //Write gboxes
            tempWriter.WriteLine(gravityBoxes.Count);
            foreach (GravityBox gbox in gravityBoxes)
            {
                tempWriter.WriteLine(gbox.box.X);
                tempWriter.WriteLine(gbox.box.Y);
                tempWriter.WriteLine(gbox.box.Width);
                tempWriter.WriteLine(gbox.box.Height);
                tempWriter.WriteLine(gbox.gravity.X);
                tempWriter.WriteLine(gbox.gravity.Y);
            }

            //Write lines

            //Sum total
            int tempcount = 0;
            foreach (List<Line> aList in lines)
                tempcount += aList.Count;

            tempWriter.WriteLine(tempcount);
            foreach (List<Line> aList in lines)
            {
                foreach (Line aLine in aList)
                {
                    tempWriter.WriteLine(aLine.getVert(1).X);
                    tempWriter.WriteLine(aLine.getVert(1).Y);
                    tempWriter.WriteLine(aLine.getVert(2).X);
                    tempWriter.WriteLine(aLine.getVert(2).Y);
                    tempWriter.WriteLine(aLine.restitution);
                }
            }

            //Write obstacles
            tempWriter.WriteLine(0);

            tempWriter.Close();
            tempWriter.Dispose();
        }


        public void clear()
        {
            //Delete ball
            if (ball != null)
                Global.level.phyWorld.RemoveBody(ball.body);
            ball = null;

            //Delete gboxes
            gravityBoxes.Clear();

            //Remove line bodies
            foreach (List<Line> l in lines)
                foreach (Line l2 in l)
                    Global.level.phyWorld.RemoveBody(l2.body);

            lines.Clear();
        }


        public void draw(SpriteBatch spriteBatch)
        {
            //Draw ball
            ball.draw(spriteBatch);

            //Draw goal
            goal.draw(spriteBatch);

            //Draw lines
            foreach (List<Line> tArray in lines)
                foreach (Line tline in tArray)
                    tline.draw(spriteBatch);

            //Draw gravity boxes
            foreach (GravityBox g in gravityBoxes)
                g.draw(spriteBatch);
        }


        public void update(GameTime gameTime)
        {
            Global.level.phyWorld.Step((float)gameTime.ElapsedGameTime.TotalMilliseconds * 0.001f);
            ball.update(gameTime);
        }


        public void reset()
        {
            ball.reset();
        }


        //Used in editor.  Deletes closest element to given coordinate
        public void deleteElementAt(Vector2 tocheck)
        {
            GravityBox toRemoveBox = null;
            List<Line> toRemoveLine = null;

            //Check for boxes to delete
            foreach (GravityBox g in gravityBoxes)
            {
                if (g.box.Contains(new Point((int)tocheck.X, (int)tocheck.Y)))
                {
                    toRemoveBox = g;
                }
            }

            //Check for lines to delete
            foreach (List<Line> tArray in lines)
            {
                foreach (Line l in tArray)
                {
                    if (l.getDistanceTo(tocheck.X, tocheck.Y) < Global.lineDeleteThreshold)
                    {
                        toRemoveLine = tArray;
                    }
                }
            }

            //Delete lines over boxes
            if (toRemoveLine != null)
                lines.Remove(toRemoveLine);
            else if (toRemoveBox != null)
                gravityBoxes.Remove(toRemoveBox);
        }
    }
}
